/*
 * @Author       : HONGKELI lihongkje@outlook.com
 * @Date         : 2024-04-24 09:31:57
 * @LastEditors  : HONGKELI lihongkje@outlook.com
 * @LastEditTime : 2024-04-25 10:01:15
 * @FilePath     : /EngMath/include/EngMath/Models/Plane.h
 * @Description  : 
  */

#ifndef PLANE_H
#define PLANE_H

#if defined(_WIN32) || defined(_WIN64)
// Platform: Windows
#define PLATFORM_WINDOWS
#elif defined(__APPLE__) || defined(__MACH__)
// Platform: macOS
#define PLATFORM_MAC
#elif defined(__linux__)
// Platform: Linux
#define PLATFORM_LINUX
#endif

#include <utility>
#include <vector>

#include <EngMath/Models/Vector3d.h>
#include <EngMath/EngMath_glob.h>

namespace EM{

/*
 * Plane class
 * Represents a plane in a three-dimensional space.
 * A plane is defined by a point and a normal vector.
 * The point is any point on the plane, and the normal vector is perpendicular to the plane.
 * The plane contains all points for which the dot product with the normal vector equals to the dot product of the normal vector and the point.
 * MATH： a(x - x0) + b(y - y0) + c(z - z0) = 0
 */
class ENGMATH_API Plane
{
public:
    // Constructs a Plane with a specified point and normal vector.
    Plane(const EM::Vector3d& point, const EM::Vector3d& normal) : point_(point), normal_(normal) {}
    // Copy constructor.
    Plane(const Plane& other) : point_(other.point_), normal_(other.normal_) {}
    // Move constructor.
    Plane(Plane&& other) noexcept : point_(std::move(other.point_)), normal_(std::move(other.normal_)) {}

public:
    
    /**
     * @description:  get  point on the plane.
     * @return {*}    point on this plane 
     */
    const EM::Vector3d& point() const { return point_; }

    /**
     * @description:  get the vector,it is normal to the plane.
     * @return {*}    vector normal in this plane
     */
    const EM::Vector3d& normal() const { return normal_; }

    /**
     * @description:              Determine a 3D point is contains in this plane
     * @param {Vector3d&} point   a point in 3D space 
     * @param {bool} isContains   if "true", point in space, "false" mean not
     * @return {*}
     */
    void contains(const EM::Vector3d& point, bool isContains) const{};

    /**
     * @description:                get ditance from a point in 3D space to this plane           
     * @param {Vector3d&} point     a point in 3D space
     * @param {double} &distance    ditance with plane
     * @return {*}                  
     */
    void compute_point_to_plane_distance(const EM::Vector3d& point, double &distance) const;

    /**
     * @description:                            get flatness 
     *   Get the average distance of all points in the set to the plane.             
     *   The smaller the flatness, the flatter the plane               
     * @param {std::vector<Vector3d>} & points  input 3d point list
     * @param {double} &double_flatness         get flatness   
     * @return {*}
     */
    void compute_flatness_average_distance(const std::vector<Vector3d>& points, double &double_flatness) const;
    
    /**
     * @description:                            get flatness 
     *  Standard Deviation                      
     * @param {std::vector<Vector3d>} & points  input 3d point list
     * @param {double} &double_flatness         get flatness   
     * @return {*}
     */
    void compute_flatness_standard_deviation_distance(const std::vector<Vector3d>& points, double &double_flatness) const;

    /**
     * @description:                            get flatness 
     *  RMS                          
     * @param {std::vector<Vector3d>} & points  input 3d point list
     * @param {double} &double_flatness         get flatness   
     * @return {*}
     */
    void compute_flatness_RMS_distance(const std::vector<Vector3d>& points, double &double_flatness) const;

    /**
     * @description:                        get randian with other plane
     * @param {Plane&} other                other plane
     * @param {double} double_randian       randian
     * @return {*}
     */
    void compute_degree(const Plane& other, double &double_degree) const;


private:
    EM::Vector3d  point_;   // A point on the plane.      
    EM::Vector3d  normal_;  // A vector normal to the plane.
};


}
#endif // PLANE_H